package com.study.service.impl;

import com.alibaba.fastjson.JSON;
import com.study.constant.AuthorityConstant;
import com.study.constant.CommonConstant;
import com.study.dao.EcommerceUserDao;
import com.study.entity.EcommerceUser;
import com.study.service.IJWTService;
import com.study.vo.LoginUserInfo;
import com.study.vo.UsernameAndPassword;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sun.misc.BASE64Decoder;

import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.UUID;

@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class IJWTServiceImpl implements IJWTService {

    @Autowired
    private EcommerceUserDao ecommerceUserDao;


    @Override
    public String generateToken(String username, String password) throws Exception {
        return generateToken(username, password, 0);
    }

    @Override
    public String generateToken(String username, String password, int expire) throws Exception {

        //需要验证用户是否能够通过授权校验
        EcommerceUser ecommerceUser = ecommerceUserDao.findByUsernameAndPassword(username, password);

        if (null == ecommerceUser) {
            log.error("cant not find user: [{}], [{}]", username, password);
            return null;
        }
        //token 中塞入对象、即 jwt中存储的信息
        LoginUserInfo loginUserInfo = new LoginUserInfo(ecommerceUser.getId(), ecommerceUser.getUsername());

        if (expire <= 0) {
            expire = AuthorityConstant.DEFAULT_EXPIRE_DAY;
        }

        //计算超时时间
        ZonedDateTime zdt = LocalDate.now().plus(expire, ChronoUnit.DAYS)
                .atStartOfDay(ZoneId.systemDefault());

        Date expireDate = Date.from(zdt.toInstant());

        return Jwts.builder()
                // jwt payload -- > kv
                .claim(CommonConstant.JWT_USER_INFO_KEY, JSON.toJSONString(loginUserInfo))
                //jwt id
                .setId(UUID.randomUUID().toString())
                //jwt 过期时间
                .setExpiration(expireDate)
                //jwt Signature --> 加密
                .signWith(getPrivateKeyky(), SignatureAlgorithm.RS256)
                .compact();
    }

    @Override
    public String registerUserAndGenerateToken(UsernameAndPassword usernameAndPassword) throws Exception {

        //如果只写这个异常、这个registerUserAndGenerateToken方法的事务也生效
        //int i = 1 / 0;

        //这个异常、这个registerUserAndGenerateToken方法的事务不生效
        //try {
        //    int i = 1 / 0;
        //}catch (Exception e){
        //    log.error("测试事务");
        //}

        EcommerceUser ecommerceUser = new EcommerceUser();
        try {
            //int i = 1 / 0;
            //测试异常、只写这种try catch写法、只要有异常、整段代码就不执行了、
            //很好体现了事务

            //校验用户名是否存在、如果存在、不能重复注册
            EcommerceUser oldUser = ecommerceUserDao.findByUsername(usernameAndPassword.getUsername());

            if (null != oldUser) {
                log.error("username is registered: [{}]", oldUser.getUsername());
                return null;
            }

            ecommerceUser.setUsername(usernameAndPassword.getUsername());
            //md5 加密之后
            ecommerceUser.setPassword(usernameAndPassword.getPassword());
            ecommerceUser.setExtraInfo("{}");
            ecommerceUser = ecommerceUserDao.save(ecommerceUser);
            log.info("register user success: [{}],[{}]", ecommerceUser.getUsername(),
                    ecommerceUser.getId());
        } catch (Exception e) {
            log.error("异常测试", e.getMessage());
        }

        return generateToken(ecommerceUser.getUsername(), ecommerceUser.getPassword());
    }

    /**
     * 根据本地存储的私钥获取 PrivateKey 对象
     * 查询相关文档
     *
     * @return
     * @throws Exception
     */
    private PrivateKey getPrivateKeyky() throws Exception {

        PKCS8EncodedKeySpec priPkCS8 = new PKCS8EncodedKeySpec(
                new BASE64Decoder().decodeBuffer(AuthorityConstant.PRIVATE_KEY));

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(priPkCS8);
    }
}
